﻿using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using Microsoft.ServiceHosting.ServiceRuntime;

using Microsoft.IdentityModel.Claims;
using Microsoft.Samples.ServiceHosting.StorageClient;
using System.Net;
using System.Data.Services.Client;
using Microsoft.IdentityModel.Web;
using System.Text.RegularExpressions;

namespace ACSWebRoleDemo_WebRole
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // Gets current identity, and checks if it is a claims-based identity, ie generated by the Geneva Framework
            IClaimsIdentity identity = Context.User.Identity as IClaimsIdentity;
            if (identity == null || identity.IsAuthenticated == false)
            {
                Response.Write("Not authenticated<br />");
            }
            else
            {
                // My scope is configured to issue an email claim if the user presents a WLID claim
                var email = (from c in identity.Claims
                             where c.ClaimType == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
                             select c.Value).First();
                if (email != null)
                {
                    // Checks if the email is already in the user table
                    StorageAccountInfo account = StorageAccountInfo.GetDefaultTableStorageAccountFromConfiguration();
                    StorageContext svc = new StorageContext(account);
                    svc.RetryPolicy = RetryPolicies.RetryN(3, TimeSpan.FromSeconds(1));
                    User user;

                    // Exception catching is, as far as I know, the only way to check if an entity exists in a table.
                    // We tried to read the entity, if it doesn't exist the Azure Storage server returns a 404 HTTP error (HttpStatusCode.NotFound)
                    try
                    {
                        user = (from u in svc.Users
                                where u.PartitionKey == "Users" && u.RowKey == email
                                select u).First();
                        // If the user was found, no exception was thrown
                        Response.Write("Registered user !<br />");
                    }
                    catch (DataServiceQueryException ex)
                    {
                        // If the user doesn't exist, we should get a 404 HTTP error
                        DataServiceClientException dsce = ex.InnerException as DataServiceClientException;
                        if (dsce != null)
                        {
                            HttpStatusCode status = (HttpStatusCode)dsce.StatusCode;
                            if (status == HttpStatusCode.NotFound)
                            {
                                // The user doesn't exist, we create it
                                Response.Write("Unregistered user !<br />");
                                user = new User();
                                user.PartitionKey = "Users";
                                user.RowKey = email;
                                svc.AddObject("Users", user);
                                svc.SaveChangesWithRetries();
                                Response.Write("User created !<br />");
                            }
                            else
                                // Exception isn't because of a 404 HTTP error, we throw it.
                                throw;
                        }
                        else
                            // Exception isn't because of a 404 HTTP error, we throw it.
                            throw;
                    }
                }
                else
                    // This should not happen, unless the scope is not correctly configured.
                    Response.Write("Oh oh ! No e-mail claim...");
            }
        }

        protected void lnkSignIn_Click(object sender, EventArgs e)
        {
            var module = FederatedAuthentication.WSFederationAuthenticationModule;
            //module.Realm = "http://localhost/FormulaireInscription";
            //module.Issuer = "https://sgunet.accesscontrol.windows.net/passivests/LiveFederation.aspx";

            // Temporary fix : gets host name from HTTP headers to avoid a bug in Windows Azure where a port number (20000) is added to Request.Url
            // Thanks to Steve Marx for this fix
            // Still left some code in case HTTP header "Host" is missing (it should be mandatory with HTTP 1.1, but I don't know much
            // about the details of HTTP, so I left it there just to be on the safe side...
            if (Request.Headers["Host"] != null)
                module.Reply = Request.Url.Scheme + "://" + Request.Headers["Host"] + Request.Url.AbsolutePath;
            else
            {
                // Uses a regex to remove port number from urls in the cloudapp domain
                Regex re = new Regex(@"(http[s]?://[\w-]*\.cloudapp\.net):[0-9]*");
                if (re.IsMatch(Request.Url.ToString()))
                    module.Reply = re.Replace(Request.Url.ToString(), "$1");
                // Used for debugging with Fiddler
                else if (Request.Url.ToString().StartsWith("http://127.0.0.1"))
                    module.Reply = this.Request.Url.ToString().Replace("127.0.0.1", "ipv4.fiddler");
                else
                    module.Reply = Request.Url.ToString();
            }

            var signin = module.CreateSignInRequest(Guid.NewGuid().ToString(), module.Reply, false);
            Response.Redirect(signin.RequestUrl);
        }

        protected void lnkDoSomething_Click(object sender, EventArgs e)
        {
            IClaimsIdentity identity = Context.User.Identity as IClaimsIdentity;
            if (identity == null || identity.IsAuthenticated == false)
            {
                Response.Write("An unauthenticated user just did something.<br />");
            }
            else
            {
                Response.Write("An authenticated user just did something.<br />");
            }
        }
    }
}
